-- Tools.lua 通用工具方法库
-- 提供各种通用功能，如TURING识别、图片查找、弹窗处理等

local TURING = require("TURING")
local config = require("Config/config")  -- 加载配置文件
local Tools = {}

-- 1. 通用TURING识别方法（支持可选切割参数）
-- 参数：区域坐标(x1,y1,x2,y2)、滤镜参数、切割参数、字库函数、期望结果、动作函数
-- 可选参数：cut_width, cut_height（如果不提供，使用默认值）
function Tools.turing_recognize_and_act(x1, y1, x2, y2, filter, cut_x, cut_y, dict_func, expect_result, action_func, cut_width, cut_height)
    -- 参数检查
    if not x1 or not y1 or not x2 or not y2 or not filter or not cut_x or not cut_y or not dict_func or not expect_result then
        print("Tools.turing_recognize_and_act: 参数检查失败")
        print("x1=" .. tostring(x1) .. ", y1=" .. tostring(y1) .. ", x2=" .. tostring(x2) .. ", y2=" .. tostring(y2))
        print("filter=" .. tostring(filter) .. ", cut_x=" .. tostring(cut_x) .. ", cut_y=" .. tostring(cut_y))
        print("dict_func=" .. tostring(dict_func) .. ", expect_result=" .. tostring(expect_result))
        return false
    end
    
    -- 使用 pcall 来捕获错误
    local ok, err = pcall(function()
        TURING.来源_获取屏幕像素(x1, y1, x2, y2)
        TURING.滤镜_彩色_二值化(filter)
    end)
    
    if not ok then
        print("TURING 调用失败: " .. tostring(err))
        return false
    end
    
    -- 根据是否提供切割宽度和高度参数来决定调用方式
    local ok2, err2 = pcall(function()
        if cut_width and cut_height then
            TURING.切割_范围投影切割(cut_x, cut_y, cut_width, cut_height)
        else
            TURING.切割_范围投影切割(cut_x, cut_y)
        end
    end)
    
    if not ok2 then
        print("TURING 切割调用失败: " .. tostring(err2))
        return false
    end
    
    local ok3, err3 = pcall(function()
        print("dict_func 类型: " .. type(dict_func))
        if type(dict_func) == "function" then
            local dict_result = dict_func()
            print("dict_func() 返回类型: " .. type(dict_result))
            if dict_result then
                print("dict_func() 返回表大小: " .. (type(dict_result) == "table" and #dict_result or "不是表"))
            end
            TURING.字库_加载六十四进制识别字库(dict_result)
        else
            print("dict_func 不是函数，而是: " .. type(dict_func))
            TURING.字库_加载六十四进制识别字库(dict_func)
        end
    end)
    
    if not ok3 then
        print("TURING 字库加载失败: " .. tostring(err3))
        return false
    end
    
    local ok4, result = pcall(function()
        return TURING.识别(70, 2)  -- 第二个参数2表示返回绝对坐标
    end)
    
    if not ok4 then
        print("TURING 识别失败: " .. tostring(result))
        return false
    end
    sleep(300) 
    print('期望结果:' .. tostring(expect_result)) 
    print('识别结果:' .. tostring(result))
    
    -- 检查识别结果
    if result == nil then
        print("TURING.识别 返回 nil")
        return false
    end
    
    if result ~= nil and result ~= "" then
        -- 解析识别结果，格式为 "文本,x坐标,y坐标|文本,x坐标,y坐标"
        local found = false
        for text_item in result:gmatch("[^|]+") do
            -- 去除首尾空格
            text_item = text_item:match("^%s*(.-)%s*$")
            local parts = {}
            for part in text_item:gmatch("[^,]+") do
                local trimmed_part = part:match("^%s*(.-)%s*$")
                table.insert(parts, trimmed_part)
            end
            
            if #parts >= 3 and parts[1] == expect_result then
                local local_x = tonumber(parts[2])
                local local_y = tonumber(parts[3])
                
                if local_x and local_y then
                    -- 将局部坐标转换为屏幕绝对坐标
                    local screen_x = x1 + local_x
                    local screen_y = y1 + local_y
                    print('局部坐标: (' .. local_x .. ',' .. local_y .. ')')
                    print('屏幕绝对坐标: (' .. screen_x .. ',' .. screen_y .. ')')
                    if action_func then
                        action_func(screen_x, screen_y)
                    end
                    found = true
                    -- 移除break，让循环继续处理所有匹配项
                end
            end
        end
        
        if found then
            return true
        elseif result == expect_result then
            -- 如果没有坐标信息，仍然调用action_func但不传参数
            if action_func then
                action_func()
            end
            return true
        end
    end
    return false
end

-- 1.1. 通用TURING识别方法（不传入期望结果，直接返回识别结果）
-- 参数：区域坐标(x1,y1,x2,y2)、滤镜参数、切割参数、字库函数
-- 可选参数：cut_width, cut_height（如果不提供，使用默认值）
-- 可选参数：confidence（识别准确度，如果不提供，使用默认值70）
-- 返回值：识别结果字符串，失败时返回 nil
function Tools.turing_recognizeAndReturnStr(x1, y1, x2, y2, filter, cut_x, cut_y, dict_func, cut_width, cut_height, confidence)
    -- 参数检查
    if not x1 or not y1 or not x2 or not y2 or not filter or not cut_x or not cut_y or not dict_func then
        print("Tools.turing_recognizeAndReturnStr: 参数检查失败")
        print("x1=" .. tostring(x1) .. ", y1=" .. tostring(y1) .. ", x2=" .. tostring(x2) .. ", y2=" .. tostring(y2))
        print("filter=" .. tostring(filter) .. ", cut_x=" .. tostring(cut_x) .. ", cut_y=" .. tostring(cut_y))
        print("dict_func=" .. tostring(dict_func))
        return nil
    end
    
    -- 使用 pcall 来捕获错误
    local ok, err = pcall(function()
        TURING.来源_获取屏幕像素(x1, y1, x2, y2)
        TURING.滤镜_彩色_二值化(filter)
    end)
    
    if not ok then
        print("TURING 调用失败: " .. tostring(err))
        return nil
    end
    
    -- 根据是否提供切割宽度和高度参数来决定调用方式
    local ok2, err2 = pcall(function()
        if cut_width and cut_height then
            TURING.切割_范围投影切割(cut_x, cut_y, cut_width, cut_height)
        else
            TURING.切割_范围投影切割(cut_x, cut_y)
        end
    end)
    
    if not ok2 then
        print("TURING 切割调用失败: " .. tostring(err2))
        return nil
    end
    
    local ok3, err3 = pcall(function()
        print("dict_func 类型: " .. type(dict_func))
        if type(dict_func) == "function" then
            local dict_result = dict_func()
            print("dict_func() 返回类型: " .. type(dict_result))
            if dict_result then
                print("dict_func() 返回表大小: " .. (type(dict_result) == "table" and #dict_result or "不是表"))
            end
            TURING.字库_加载六十四进制识别字库(dict_result)
        else
            print("dict_func() 不是函数，而是: " .. type(dict_func))
            TURING.字库_加载六十四进制识别字库(dict_func)
        end
    end)
    
    if not ok3 then
        print("TURING 字库加载失败: " .. tostring(err3))
        return nil
    end
    
    -- 设置默认准确度值
    confidence = confidence or 70
    
    local ok4, result = pcall(function()
        return TURING.识别(confidence)  -- 第一个参数是准确度，第二个参数2表示返回绝对坐标
    end)
    
    if not ok4 then
        print("TURING 识别失败: " .. tostring(result))
        return nil
    end
    
    sleep(300) 
    print('识别结果: ' .. tostring(result))
    
    -- 检查识别结果
    if result == nil or result == "" then
        print("TURING.识别 返回空结果")
        return nil
    end
    
    -- 直接返回识别结果字符串
    return result
end



-- 2. 通用图片查找与点击方法
-- 参数：查找区域(x1,y1,x2,y2)、图片名、颜色、相似度
function Tools.find_and_tap(x1, y1, x2, y2, image, color, sim)
    local index, x, y = findPic(x1, y1, x2, y2, image, color or "000000", 0, sim or 0.9)
    if index ~= -1 then
        tap(x, y)
        print("点击图片: " .. image .. " 坐标: (" .. x .. "," .. y .. ")")
        return true, x, y
    end
    return false, 0, 0
end

-- 3. 通用弹窗处理方法
-- 参数：查找区域、图片名、颜色、相似度、点击后等待时间
function Tools.handle_popup(x1, y1, x2, y2, image, color, sim, sleep_time)
    local success, x, y = Tools.find_and_tap(x1, y1, x2, y2, image, color, sim)
    if success then
        print("已处理弹窗: " .. image)
        sleep(sleep_time or 1000)
        return true
    end
    return false
end

-- 4. 通用滑动查找方法
-- 参数：最大滑动次数、滑动函数、查找函数
function Tools.swipe_and_find(max_swipe, swipe_func, find_func)
    for i = 1, max_swipe do
        if find_func() then
            return true
        end
        swipe_func()
        sleep(1000)
    end
    return false
end

-- 5. 通用滚动查找单个文字并返回坐标的方法
-- 参数：
--   target_text: 要查找的文字
--   scroll_area: 滚动区域坐标 {x1, y1, x2, y2}
--   filter_params: 滤镜参数（可以是单个字符串或字符串数组）
--   cut_params: 切割参数
--   dict_func: 字库函数
-- 返回值：找到时返回 x, y 坐标，未找到时返回 nil, nil
function Tools.scroll_find_text(target_text, scroll_area, filter_params, cut_params, dict_func)
    -- 参数验证
    if not target_text or not scroll_area or not filter_params or not cut_params or not dict_func then
        print("错误：scroll_find_text 参数不完整")
        print("target_text = " .. tostring(target_text))
        print("scroll_area = " .. tostring(scroll_area))
        print("filter_params = " .. tostring(filter_params))
        print("cut_params = " .. tostring(cut_params))
        print("dict_func = " .. tostring(dict_func))
        return nil, nil
    end
    
    -- 将单个filter_params转换为数组，保持向后兼容
    local filter_params_list = type(filter_params) == "table" and filter_params or {filter_params}
    return Tools.scroll_find_text_internal(target_text, scroll_area, filter_params_list, cut_params, dict_func)
end

-- 5.1. 支持多个filter_params的滚动查找方法
-- 参数：
--   target_text: 要查找的文字
--   scroll_area: 滚动区域坐标 {x1, y1, x2, y2}
--   filter_params_list: 滤镜参数列表，如 {"0-114", "0-46"}
--   cut_params: 切割参数
--   dict_func: 字库函数
-- 返回值：找到时返回 x, y 坐标，未找到时返回 nil, nil
function Tools.scroll_find_text_multi_filter(target_text, scroll_area, filter_params_list, cut_params, dict_func)
    -- 参数验证
    if not target_text or not scroll_area or not filter_params_list or not cut_params or not dict_func then
        print("错误：scroll_find_text_multi_filter 参数不完整")
        print("target_text = " .. tostring(target_text))
        print("scroll_area = " .. tostring(scroll_area))
        print("filter_params_list = " .. tostring(filter_params_list))
        print("cut_params = " .. tostring(cut_params))
        print("dict_func = " .. tostring(dict_func))
        return nil, nil
    end
    
    return Tools.scroll_find_text_internal(target_text, scroll_area, filter_params_list, cut_params, dict_func)
end

-- 5.2. 内部滚动查找实现（统一逻辑）
-- 参数：
--   target_text: 要查找的文字
--   scroll_area: 滚动区域坐标 {x1, y1, x2, y2}
--   filter_params_list: 滤镜参数列表
--   cut_params: 切割参数
--   dict_func: 字库函数
-- 返回值：找到时返回 x, y 坐标，未找到时返回 nil, nil
function Tools.scroll_find_text_internal(target_text, scroll_area, filter_params_list, cut_params, dict_func)
    print("开始滚动查找文字: " .. target_text .. " (多滤镜参数)")
    
    -- 参数验证
    if not scroll_area or not scroll_area.x1 or not scroll_area.y1 or not scroll_area.x2 or not scroll_area.y2 then
        print("错误：scroll_area 参数无效")
        print("scroll_area = " .. tostring(scroll_area))
        if scroll_area then
            print("x1 = " .. tostring(scroll_area.x1))
            print("y1 = " .. tostring(scroll_area.y1))
            print("x2 = " .. tostring(scroll_area.x2))
            print("y2 = " .. tostring(scroll_area.y2))
        end
        return nil, nil
    end
    
    -- 计算滑动参数
    local scroll_height = scroll_area.y2 - scroll_area.y1
    local swipe_distance = math.floor(scroll_height * 0.8)  -- 增加滑动距离到80%
    local scroll_center_x = (scroll_area.x1 + scroll_area.x2) / 2
    
    -- 向上滑动到顶部函数（从上往下滑动手指，内容向上移动）
    local function swipe_to_top()
        print("向上滑动到顶部（内容向上移动）")
        swipe(scroll_center_x, scroll_area.y1 + 50, scroll_center_x, scroll_area.y2 - 50, 500)
        sleep(1000)
    end
    
    -- 向下滑动函数（内容向上移动）
    local function swipe_down()
        print("向下滑动查找（内容向上移动）")
        local start_y = scroll_area.y1 + swipe_distance
        local end_y = scroll_area.y1 + 100
        print("滑动从 (" .. scroll_center_x .. "," .. start_y .. ") 到 (" .. scroll_center_x .. "," .. end_y .. ")")
        print("滑动区域: x1=" .. scroll_area.x1 .. ", y1=" .. scroll_area.y1 .. ", x2=" .. scroll_area.x2 .. ", y2=" .. scroll_area.y2)
        print("滑动距离: " .. swipe_distance .. " 像素")
        swipe(scroll_center_x, start_y, scroll_center_x, end_y, 800)
        sleep(1000)
    end
    
    -- 使用指定filter_params查找目标文字的函数
    local function find_text_with_filter(filter_params)
        local found_x, found_y = nil, nil
        local success = Tools.turing_recognize_and_act(
            scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2, 
            filter_params, cut_params.x, cut_params.y,
            dict_func, target_text, 
            function(x, y)
                found_x, found_y = x, y
                print("找到文字: " .. target_text .. " 坐标: (" .. x .. "," .. y .. ") 使用filter_params: " .. filter_params)
                return true
            end, cut_params.width, cut_params.height
        )
        return success, found_x, found_y
    end
    
    -- 检查是否到达顶部（通过比较滑动前后的画面，排除公屏通知区域）
    local function check_is_at_top()
        print("通过画面比较检查是否到达顶部（排除公屏通知区域）")
        
        local notification_area = {x1 = 304, y1 = 137, x2 = 1051, y2 = 186}  -- 公屏通知区域
        
        -- 获取滑动前的画面（排除公屏通知区域）
        local before_screenshot = getScreenPixel(scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2)
        if not before_screenshot then
            print("无法获取滑动前画面，检查失败")
            return false
        end
        
        -- 向上滑动
        swipe_to_top()
        sleep(1000)  -- 等待画面稳定
        
        -- 获取滑动后的画面（排除公屏通知区域）
        local after_screenshot = getScreenPixel(scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2)
        if not after_screenshot then
            print("无法获取滑动后画面，检查失败")
            return false
        end
        
        -- 比较两个画面是否相同（排除公屏通知区域）
        local is_same = Tools.compare_screenshots_excluding_area(before_screenshot, after_screenshot, notification_area, scroll_area)
        print("画面比较结果（排除公屏通知区域）: " .. (is_same and "相同" or "不同"))
        
        if is_same then
            print("画面无变化，确认已到达顶部")
            return true
        else
            print("画面有变化，继续向上滑动")
            return false
        end
    end
    
    -- 检查是否到达底部（通过比较滑动前后的画面，排除公屏通知区域）
    local function check_is_at_bottom()
        print("通过画面比较检查是否到达底部（排除公屏通知区域）")
        
        local notification_area = {x1 = 304, y1 = 137, x2 = 1051, y2 = 186}  -- 公屏通知区域
        
        -- 获取滑动前的画面（排除公屏通知区域）
        local before_screenshot = getScreenPixel(scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2)
        if not before_screenshot then
            print("无法获取滑动前画面，检查失败")
            return false
        end
        
        -- 向下滑动
        swipe_down()
        sleep(1000)  -- 等待画面稳定
        
        -- 获取滑动后的画面（排除公屏通知区域）
        local after_screenshot = getScreenPixel(scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2)
        if not after_screenshot then
            print("无法获取滑动后画面，检查失败")
            return false
        end
        
        -- 比较两个画面是否相同（排除公屏通知区域）
        local is_same = Tools.compare_screenshots_excluding_area(before_screenshot, after_screenshot, notification_area, scroll_area)
        print("画面比较结果（排除公屏通知区域）: " .. (is_same and "相同" or "不同"))
        
        if is_same then
            print("画面无变化，确认已到达底部")
            return true
        else
            print("画面有变化，继续向下滑动")
            return false
        end
    end
    
    -- 主查找逻辑
    local has_searched_current_area = false  -- 标记是否已经搜索过当前区域
    local is_at_top = false
    local is_at_bottom = false
    local attempts = 0
    
    while true do
        attempts = attempts + 1
        print("第 " .. attempts .. " 次尝试查找: " .. target_text)
        
        -- 对每个filter_params依次尝试查找
        for i, filter_params in ipairs(filter_params_list) do
            print("尝试使用filter_params: " .. filter_params)
            local success, x, y = find_text_with_filter(filter_params)
            if success then
                print("成功找到文字: " .. target_text .. " 使用filter_params: " .. filter_params)
                return x, y
            else
                print("使用filter_params " .. filter_params .. " 未找到文字: " .. target_text)
                if i < #filter_params_list then
                    print("继续尝试下一个filter_params...")
                end
            end
        end
        
        -- 如果所有filter_params都没找到，需要滚动查找
        if not has_searched_current_area then
            -- 第一次搜索当前区域没找到，先向下滑动查找一次
            print("当前区域未找到，先向下滑动查找一次")
            swipe_down()
            sleep(1500)  -- 滑动后稍作等待，让界面稳定
            has_searched_current_area = true
        elseif not is_at_top then
            -- 已经向下滑动过，现在需要返回到顶部
            print("向下滑动后仍未找到，现在返回到顶部")
            print("开始向上滑动直到到达顶部...")
            while not check_is_at_top() do
                print("继续向上滑动...")
                swipe_to_top()
                sleep(1000)  -- 等待画面稳定
            end
            is_at_top = true
            print("已到达顶部")
        else
            -- 已经到达顶部，继续向下滑动查找
            if not is_at_bottom then
                -- 检查是否到达底部
                if check_is_at_bottom() then
                    is_at_bottom = true
                    print("已到达底部，搜索完成")
                    break  -- 退出循环，搜索完成
                else
                    -- 继续向下滑动查找
                    swipe_down()
                    sleep(1500)  -- 滑动后稍作等待，让界面稳定
                end
            else
                -- 已经到达底部，搜索完成
                print("已到达底部，搜索完成")
                break  -- 退出循环，搜索完成
            end
        end
    end
    
    print("未找到文字: " .. target_text .. "，已尝试 " .. attempts .. " 次，已搜索完整个滚动区域（从顶部到底部）")
    return nil, nil
end

-- 通用滑动查找指定数量文字的方法
-- 参数说明：
-- target_text: 要查找的目标文字
-- scroll_area: 滚动区域坐标 {x1, y1, x2, y2}
-- filter_params: 滤镜参数
-- cut_params: 切割参数 {x, y, width, height}
-- dict_func: 字库函数
-- required_count: 需要找到的数量
-- 返回值: 找到指定数量文字的坐标数组，未找到返回空数组
function Tools.scroll_find_text_count(target_text, scroll_area, filter_params, cut_params, dict_func, required_count)
    print("开始滚动查找文字: " .. target_text .. "，需要找到 " .. required_count .. " 个")
    
    -- 参数验证
    if not target_text or not scroll_area or not filter_params or not cut_params or not dict_func or not required_count then
        print("错误：scroll_find_text_count 参数不完整")
        print("target_text = " .. tostring(target_text))
        print("scroll_area = " .. tostring(scroll_area))
        print("filter_params = " .. tostring(filter_params))
        print("cut_params = " .. tostring(cut_params))
        print("dict_func = " .. tostring(dict_func))
        print("required_count = " .. tostring(required_count))
        return {}
    end
    
    if required_count <= 0 then
        print("错误：required_count 必须大于0")
        return {}
    end
    
    -- 将单个filter_params转换为数组格式
    local filter_params_list = {filter_params}
    
    -- 存储找到的所有结果
    local found_results = {}
    local attempts = 0
    local max_attempts = 50  -- 最大尝试次数，防止无限循环
    
    -- 计算滑动参数
    local scroll_height = scroll_area.y2 - scroll_area.y1
    local swipe_distance = math.floor(scroll_height * 0.8)
    local scroll_center_x = (scroll_area.x1 + scroll_area.x2) / 2
    
    -- 向上滑动到顶部函数
    local function swipe_to_top()
        print("向上滑动到顶部（内容向上移动）")
        swipe(scroll_center_x, scroll_area.y1 + 50, scroll_center_x, scroll_area.y2 - 50, 500)
        sleep(1000)
    end
    
    -- 向下滑动函数
    local function swipe_down()
        print("向下滑动查找（内容向上移动）")
        local start_y = scroll_area.y1 + swipe_distance
        local end_y = scroll_area.y1 + 100
        swipe(scroll_center_x, start_y, scroll_center_x, end_y, 800)
        sleep(1000)
    end
    
    -- 使用指定filter_params查找目标文字的函数（查找所有匹配项）
    local function find_text_with_filter(filter_params)
        local found_count_before = #found_results
        local success = Tools.turing_recognize_and_act(
            scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2, 
            filter_params, cut_params.x, cut_params.y,
            dict_func, target_text, 
            function(x, y)
                local found_count = #found_results + 1
                print("找到第 " .. found_count .. " 个文字: " .. target_text .. " 坐标: (" .. x .. "," .. y .. ") 使用filter_params: " .. filter_params)
                
                -- 添加到结果数组
                table.insert(found_results, {x = x, y = y})
                
                -- 不要在这里停止，让TURING继续识别当前画面中的所有匹配项
                -- 只有当找到的数量超过所需数量的2倍时才停止（避免无限循环）
                if #found_results >= required_count * 2 then
                    print("找到数量已超过所需数量的2倍，停止继续识别: " .. #found_results .. "/" .. required_count)
                    return true
                end
                
                return false  -- 继续查找更多匹配项
            end, cut_params.width, cut_params.height
        )
        
        local found_count_after = #found_results
        local new_found = found_count_after - found_count_before
        print("本次识别新增找到: " .. new_found .. " 个，总计: " .. found_count_after .. "/" .. required_count)
        
        return success, new_found
    end
    
    -- 检查是否到达顶部
    local function check_is_at_top()
        print("通过画面比较检查是否到达顶部")
        
        local notification_area = {x1 = 304, y1 = 137, x2 = 1051, y2 = 186}
        
        local before_screenshot = getScreenPixel(scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2)
        if not before_screenshot then
            print("无法获取滑动前画面，检查失败")
            return false
        end
        
        swipe_to_top()
        sleep(1000)
        
        local after_screenshot = getScreenPixel(scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2)
        if not after_screenshot then
            print("无法获取滑动后画面，检查失败")
            return false
        end
        
        local is_same = Tools.compare_screenshots_excluding_area(before_screenshot, after_screenshot, notification_area, scroll_area)
        print("画面比较结果: " .. (is_same and "相同" or "不同"))
        
        return is_same
    end
    
    -- 检查是否到达底部
    local function check_is_at_bottom()
        print("通过画面比较检查是否到达底部")
        
        local notification_area = {x1 = 304, y1 = 137, x2 = 1051, y2 = 186}
        
        local before_screenshot = getScreenPixel(scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2)
        if not before_screenshot then
            print("无法获取滑动前画面，检查失败")
            return false
        end
        
        swipe_down()
        sleep(1000)
        
        local after_screenshot = getScreenPixel(scroll_area.x1, scroll_area.y1, scroll_area.x2, scroll_area.y2)
        if not after_screenshot then
            print("无法获取滑动后画面，检查失败")
            return false
        end
        
        local is_same = Tools.compare_screenshots_excluding_area(before_screenshot, after_screenshot, notification_area, scroll_area)
        print("画面比较结果: " .. (is_same and "相同" or "不同"))
        
        return is_same
    end
    
    -- 主查找逻辑
    local has_searched_current_area = false
    local is_at_top = false
    local is_at_bottom = false
    
    while #found_results < required_count and attempts < max_attempts do
        attempts = attempts + 1
        print("第 " .. attempts .. " 次尝试查找: " .. target_text .. "，当前已找到: " .. #found_results .. "/" .. required_count)
        
        -- 对每个filter_params依次尝试查找
        for i, filter_params in ipairs(filter_params_list) do
            print("尝试使用filter_params: " .. filter_params)
            local success, found_count = find_text_with_filter(filter_params)
            
            print("当前已找到总数: " .. #found_results .. "/" .. required_count)
            
            if #found_results >= required_count then
                print("已找到足够的数量，停止查找")
                break
            end
            
            if not success then
                print("使用filter_params " .. filter_params .. " 未找到文字: " .. target_text)
            end
        end
        
        -- 如果已经找到足够的数量，退出循环
        if #found_results >= required_count then
            print("当前画面已找到足够的数量，无需继续滚动")
            break
        end
        
        -- 如果所有filter_params都没找到，需要滚动查找
        if not has_searched_current_area then
            print("当前区域未找到，先向下滑动查找一次")
            swipe_down()
            sleep(1500)
            has_searched_current_area = true
        elseif not is_at_top then
            print("向下滑动后仍未找到，现在返回到顶部")
            print("开始向上滑动直到到达顶部...")
            while not check_is_at_top() do
                print("继续向上滑动...")
                swipe_to_top()
                sleep(1000)  -- 等待画面稳定
            end
            is_at_top = true
            print("已到达顶部")
        else
            if not is_at_bottom then
                if check_is_at_bottom() then
                    is_at_bottom = true
                    print("已到达底部，搜索完成")
                    break
                else
                    swipe_down()
                    sleep(1500)
                end
            else
                print("已到达底部，搜索完成")
                break
            end
        end
    end
    
    if #found_results >= required_count then
        print("成功找到 " .. #found_results .. " 个文字: " .. target_text)
        -- 只返回需要的数量
        local result = {}
        for i = 1, required_count do
            table.insert(result, found_results[i])
        end
        return result
    else
        print("未找到足够的文字: " .. target_text .. "，只找到 " .. #found_results .. " 个，需要 " .. required_count .. " 个")
        return found_results
    end
end

-- 5. 通用状态切换方法
-- 参数：新状态
function Tools.switch_state(newState)
    local config = require('Config/config')
    config.gameState = newState
    print("切换状态为: " .. tostring(newState))
end

-- 6. 通用日志输出方法
function Tools.log(msg, level)
    local level_str = level or "INFO"
    local timestamp = os.date("%H:%M:%S")
    print("[" .. timestamp .. "] [" .. level_str .. "] " .. msg)
end

-- 7. 通用等待和重试方法
function Tools.wait_and_retry(max_retries, condition_func, action_func, sleep_time)
    for i = 1, max_retries do
        if condition_func() then
            if action_func then
                action_func()
            end
            return true
        end
        sleep(sleep_time or 1000)
    end
    return false
end

-- 8. 通用坐标点击方法
function Tools.safe_tap(x, y, description)
    if x and y then
        tap(x, y)
        print("点击" .. (description or "坐标") .. ": (" .. x .. "," .. y .. ")")
        return true
    end
    return false
end

-- 8.1. 通用按钮点击方法
-- 参数:
-- target_text: 目标文字
-- button_name: 按钮名称 (用于日志输出)
-- step_number: 步骤编号 (用于日志输出)
-- x1, y1, x2, y2: 按钮区域坐标
-- filter_params: 滤镜参数
-- cut_x, cut_y: 切割参数
-- dict_func: 字库函数 (必需参数)
-- cut_width, cut_height: 切割宽度和高度 (可选参数)
function Tools.click_button(target_text, button_name, step_number, x1, y1, x2, y2, filter_params, cut_x, cut_y, dict_func, cut_width, cut_height)
    print(step_number .. "-检测并点击" .. button_name .. "按钮")
    
    -- 检查字库函数是否提供
    if not dict_func then
        print("错误：必须提供字库函数参数")
        return false
    end
    
    -- 根据是否提供切割宽度和高度参数来决定调用方式
    local flag
    if cut_width and cut_height then
        flag = Tools.turing_recognize_and_act(
            x1, y1, x2, y2,           -- 按钮区域坐标
            filter_params,            -- 滤镜参数
            cut_x, cut_y,             -- 切割参数
            dict_func,                -- 字库函数
            target_text,              -- 目标文字
            function(x, y)
                tap(x, y)
                sleep(config.SLEEP_TIME)
            end,
            cut_width, cut_height     -- 切割宽度和高度
        )
    else
        flag = Tools.turing_recognize_and_act(
            x1, y1, x2, y2,           -- 按钮区域坐标
            filter_params,            -- 滤镜参数
            cut_x, cut_y,             -- 切割参数
            dict_func,                -- 字库函数
            target_text,              -- 目标文字
            function(x, y)
                tap(x, y)
                sleep(config.SLEEP_TIME)
            end
        )
    end
    
    return flag
end

-- 带偏移量点击的通用方法
-- 参数说明：
-- target_text: 目标文字
-- button_name: 按钮名称（用于日志）
-- step_number: 步骤编号（用于日志）
-- x1, y1, x2, y2: 按钮区域坐标
-- filter_params: 滤镜参数
-- cut_x, cut_y: 切割参数
-- dict_func: 字库函数 (必需参数)
-- offset_x, offset_y: 点击偏移量（相对于找到的文字坐标）
-- cut_width, cut_height: 切割宽度和高度 (可选参数)
function Tools.click_button_with_offset(target_text, button_name, step_number, x1, y1, x2, y2, filter_params, cut_x, cut_y, dict_func, offset_x, offset_y, cut_width, cut_height)
    print(step_number .. "-检测并点击" .. button_name .. "按钮（带偏移量）")
    
    -- 检查字库函数是否提供
    if not dict_func then
        print("错误：必须提供字库函数参数")
        return false
    end
    
    -- 根据是否提供切割宽度和高度参数来决定调用方式
    local flag
    if cut_width and cut_height then
        flag = Tools.turing_recognize_and_act(
            x1, y1, x2, y2,           -- 按钮区域坐标
            filter_params,            -- 滤镜参数
            cut_x, cut_y,             -- 切割参数
            dict_func,                -- 字库函数
            target_text,              -- 目标文字
            function(x, y)
                -- 计算偏移后的点击坐标
                local click_x = x + offset_x
                local click_y = y + offset_y
                print("找到文字坐标: (" .. x .. "," .. y .. ")，偏移后点击坐标: (" .. click_x .. "," .. click_y .. ")")
                tap(click_x, click_y)
                sleep(config.SLEEP_TIME)
            end,
            cut_width, cut_height     -- 切割宽度和高度
        )
    else
        flag = Tools.turing_recognize_and_act(
            x1, y1, x2, y2,           -- 按钮区域坐标
            filter_params,            -- 滤镜参数
            cut_x, cut_y,             -- 切割参数
            dict_func,                -- 字库函数
            target_text,              -- 目标文字
            function(x, y)
                -- 计算偏移后的点击坐标
                local click_x = x + offset_x
                local click_y = y + offset_y
                print("找到文字坐标: (" .. x .. "," .. y .. ") 偏移后点击坐标: (" .. click_x .. "," .. click_y .. ")")
                tap(click_x, click_y)
                sleep(config.SLEEP_TIME)
            end
        )
    end
    
    return flag
end

-- 9. 通用字符串处理方法
function Tools.is_empty_or_nil(str)
    return str == nil or str == ""
end

function Tools.safe_concat(...)
    local args = {...}
    local result = ""
    for i, arg in ipairs(args) do
        if arg ~= nil then
            result = result .. tostring(arg)
        end
    end
    return result
end

-- 10. 通用数组/表处理方法
function Tools.table_contains(tbl, value)
    for _, v in pairs(tbl) do
        if v == value then
            return true
        end
    end
    return false
end

function Tools.table_length(tbl)
    local count = 0
    for _ in pairs(tbl) do
        count = count + 1
    end
    return count
end

-- 11. 通用错误处理方法
function Tools.safe_call(func, ...)
    local ok, result = pcall(func, ...)
    if not ok then
        Tools.log("函数调用失败: " .. tostring(result), "ERROR")
        return nil
    end
    return result
end

-- 12. 通用时间处理方法
function Tools.get_current_time()
    return os.date("%Y-%m-%d %H:%M:%S")
end

function Tools.format_duration(seconds)
    local hours = math.floor(seconds / 3600)
    local minutes = math.floor((seconds % 3600) / 60)
    local secs = seconds % 60
    return string.format("%02d:%02d:%02d", hours, minutes, secs)
end

-- 13. 通用配置验证方法
function Tools.validate_config(config_table, required_fields)
    for _, field in ipairs(required_fields) do
        if config_table[field] == nil then
            Tools.log("配置缺少必需字段: " .. field, "ERROR")
            return false
        end
    end
    return true
end

-- 14. 通用调试方法
function Tools.debug_print_table(tbl, indent)
    indent = indent or 0
    for k, v in pairs(tbl) do
        local formatting = string.rep("  ", indent) .. k .. ": "
        if type(v) == "table" then
            print(formatting)
            Tools.debug_print_table(v, indent + 1)
        else
            print(formatting .. tostring(v))
        end
    end
end

-- 15. 通用性能监控方法
function Tools.measure_time(func, description)
    local start_time = os.clock()
    local result = func()
    local end_time = os.clock()
    local duration = end_time - start_time
    Tools.log(description .. " 耗时: " .. string.format("%.3f", duration) .. "秒", "DEBUG")
    return result, duration
end

-- 比较两个截图，排除指定区域
-- 参数：
--   screenshot1: 第一个截图
--   screenshot2: 第二个截图
--   exclude_area: 要排除的区域 {x1, y1, x2, y2}
--   scroll_area: 滚动区域 {x1, y1, x2, y2}
-- 返回值：如果排除指定区域后两个截图相同返回true，否则返回false
function Tools.compare_screenshots_excluding_area(screenshot1, screenshot2, exclude_area, scroll_area)
    if not screenshot1 or not screenshot2 then
        print("截图数据为空，无法比较")
        return false
    end
    
    -- 如果两个截图完全相同，直接返回true
    if screenshot1 == screenshot2 then
        return true
    end
    
    -- 检查排除区域是否与滚动区域有重叠
    local has_overlap = not (exclude_area.x1 >= scroll_area.x2 or exclude_area.x2 <= scroll_area.x1 or
                             exclude_area.y1 >= scroll_area.y2 or exclude_area.y2 <= scroll_area.y1)
    
    if not has_overlap then
        print("公屏通知区域在滚动区域外，使用原始比较结果")
        return screenshot1 == screenshot2
    end
    
    -- 如果有重叠，我们需要更智能的比较策略
    -- 由于Lua中无法直接操作截图像素数据，我们采用以下策略：
    -- 1. 如果截图不完全相同，但差异很小，可能是公屏通知导致的
    -- 2. 在这种情况下，我们假设它们是相同的（因为公屏通知不应该影响滚动检测）
    
    print("公屏通知区域与滚动区域重叠，采用智能比较策略")
    print("公屏通知区域: (" .. exclude_area.x1 .. ", " .. exclude_area.y1 .. ") - (" .. exclude_area.x2 .. ", " .. exclude_area.y2 .. ")")
    print("滚动区域: (" .. scroll_area.x1 .. ", " .. scroll_area.y1 .. ") - (" .. scroll_area.x2 .. ", " .. scroll_area.y2 .. ")")
    
    -- 临时策略：如果截图不完全相同，但排除区域确实在滚动区域内，我们假设差异是由公屏通知引起的
    -- 在实际应用中，这里应该实现真正的像素级比较，排除指定区域
    print("假设差异由公屏通知引起，认为画面相同")
    return true
end

-- 模糊字符串匹配函数，用于处理OCR识别错误
function Tools.fuzzy_match(target, candidates)
    if not target or not candidates then
        return false, nil
    end
    
    -- 如果candidates是字符串，转换为数组
    if type(candidates) == "string" then
        candidates = {candidates}
    end
    
    -- 完全匹配
    for i, candidate in ipairs(candidates) do
        if candidate == target then
            return true, candidate
        end
    end
    
    -- 模糊匹配：检查是否包含目标字符串
    for i, candidate in ipairs(candidates) do
        if type(candidate) == "string" and type(target) == "string" and (string.find(candidate, target) or string.find(target, candidate)) then
            return true, candidate
        end
    end
    
    -- 相似度匹配：计算编辑距离
    local best_match = nil
    local best_similarity = 0
    
    for i, candidate in ipairs(candidates) do
        local similarity = Tools.calculate_similarity(target, candidate)
        if similarity > best_similarity and similarity >= 0.7 then  -- 70%相似度阈值
            best_similarity = similarity
            best_match = candidate
        end
    end
    
    if best_match then
        print("模糊匹配成功:", target, "->", best_match, "相似度:", string.format("%.2f", best_similarity))
        return true, best_match
    end
    
    return false, nil
end

-- 计算两个字符串的相似度（基于编辑距离）
function Tools.calculate_similarity(str1, str2)
    if not str1 or not str2 then
        return 0
    end
    
    local len1, len2 = #str1, #str2
    local max_len = math.max(len1, len2)
    
    if max_len == 0 then
        return 1
    end
    
    -- 简单的相似度计算：共同字符数 / 最大长度
    local common_chars = 0
    for i = 1, len1 do
        local char1 = string.sub(str1, i, i)
        for j = 1, len2 do
            local char2 = string.sub(str2, j, j)
            if char1 == char2 then
                common_chars = common_chars + 1
                break
            end
        end
    end
    
    return common_chars / max_len
end

-- 验证数字格式是否正确
-- 参数：str - 要验证的字符串
-- 返回值：true 表示格式正确，false 表示格式错误
-- 正确格式示例：80,10、0,,80、100,200、50,,,60 等
function Tools.is_valid_number_format(str)
    if not str or str == "" then
        return false
    end
    
    -- 去除首尾空格
    str = str:match("^%s*(.-)%s*$")
    
    -- 检查是否包含问号
    if string.find(str, "?") then
        print("格式验证失败：包含问号")
        return false
    end
    
    -- 检查是否只包含数字、逗号和空格
    if not str:match("^[0-9,%s]*$") then
        print("格式验证失败：包含非法字符")
        return false
    end
    
    -- 按逗号分割字符串
    local parts = {}
    for part in str:gmatch("[^,]+") do
        local trimmed_part = part:match("^%s*(.-)%s*$")
        if trimmed_part ~= "" then
            table.insert(parts, trimmed_part)
        end
    end
    
    -- 检查分割后的部分数量
    if #parts < 2 then
        print("格式验证失败：至少需要两个数字部分")
        return false
    end
    
    -- 检查每个部分是否都是有效的数字
    for i, part in ipairs(parts) do
        if not part:match("^%s*[0-9]+%s*$") then
            print("格式验证失败：部分 '" .. part .. "' 不是有效数字")
            return false
        end
    end
    
    print("格式验证成功：'" .. str .. "' 包含 " .. #parts .. " 个数字部分")
    return true
end

-- 数字键盘布局映射
local numpad_pos = {
    ["1"] = {row=3, col=1},
    ["2"] = {row=3, col=2},
    ["3"] = {row=3, col=3},
    ["4"] = {row=2, col=1},
    ["5"] = {row=2, col=2},
    ["6"] = {row=2, col=3},
    ["7"] = {row=1, col=1},
    ["8"] = {row=1, col=2},
    ["9"] = {row=1, col=3},
    ["0"] = {row=4, col=1},
}

-- 基准点（5键中心）
local base_x, base_y = 601, 316
local cell_w, cell_h = 70, 40
--输入数字
function Tools.InputNumber(number)
    local num_str = tostring(number)
    for i = 1, #num_str do
        local digit = num_str:sub(i, i)
        local pos = numpad_pos[digit]
        if pos then
            local x = base_x + (pos.col - 2) * cell_w
            local y = base_y + (pos.row - 2) * cell_h
            tap(x, y)
            sleep(500) -- 可根据实际情况调整
        else
            print("不支持的数字: " .. digit)
        end
    end
    tap(735,500)--确认
    sleep(500)
end

-- 递归打印表内容的方法
-- 参数：table_data - 要打印的表数据
-- 参数：indent - 缩进级别（可选，默认为0）
-- 参数：max_depth - 最大打印深度（可选，默认为5）
function Tools.print_table(table_data, indent, max_depth)
    indent = indent or 0
    max_depth = max_depth or 5
    
    -- 检查参数是否为nil
    if table_data == nil then
        print(string.rep("  ", indent) .. "nil")
        return
    end
    
    if indent > max_depth then
        print(string.rep("  ", indent) .. "... (达到最大深度)")
        return
    end
    
    if type(table_data) ~= "table" then
        print(string.rep("  ", indent) .. tostring(table_data))
        return
    end
    
    -- 使用pcall来安全地遍历表
    local success, err = pcall(function()
        for key, value in pairs(table_data) do
            local key_str = tostring(key)
            if value == nil then
                print(string.rep("  ", indent) .. key_str .. ": nil")
            elseif type(value) == "table" then
                print(string.rep("  ", indent) .. key_str .. ": table")
                Tools.print_table(value, indent + 1, max_depth)
            else
                print(string.rep("  ", indent) .. key_str .. ": " .. tostring(value))
            end
        end
    end)
    
    if not success then
        print(string.rep("  ", indent) .. "错误: " .. tostring(err))
    end
end

-- 打印表内容的便捷方法
-- 参数：table_data - 要打印的表数据
-- 参数：title - 可选的标题（可选）
function Tools.print_table_content(table_data, title)
    if title then
        print("=== " .. title .. " ===")
    else
        print("=== 表内容 ===")
    end
    
    -- 检查输入参数
    if table_data == nil then
        print("  警告: 输入数据为nil")
    elseif type(table_data) ~= "table" then
        print("  数据类型: " .. type(table_data))
        print("  数据内容: " .. tostring(table_data))
    else
        Tools.print_table(table_data, 0, 5)
    end
    
    if title then
        print("=== " .. title .. " 结束 ===")
    else
        print("=== 表内容结束 ===")
    end
end

-- 通用数字识别方法（使用正确的TURING语法）
-- 参数：
--   x1, y1, x2, y2: 识别区域坐标
--   filter_range: 滤镜范围，如 "0-166"
--   cut_x, cut_y: 切割参数（如果都是-1，则使用连通切割方式）
--   dict_func: 字库函数
--   confidence: 识别置信度（可选，默认为75）
-- 返回值：识别到的数字，如果识别失败返回nil
function Tools.recognize_number_in_range(x1, y1, x2, y2, filter_range, cut_x, cut_y, dict_func, confidence)
    print("Tools.recognize_number_in_range")
    
    -- 设置默认值
    confidence = confidence or 75    
    --TURING.滤镜_通用_延伸裁剪(x1, y1, x2, y2)
    TURING.来源_获取屏幕像素(x1, y1, x2, y2)
    -- TURING.来源_获取屏幕像素(0,0,100,100)    -- 仅备用！
    TURING.滤镜_彩色_二值化("C7D7DC-202020|A4B1B6-101010|2D68C4-101010|3061AE-101010|3072DA-101010")
    if cut_x == -1 and cut_y == -1 then 
        TURING.切割_连通区域切割(true)    -- [VIP]  
    else
        TURING.切割_范围切割(cut_x, cut_y)
    end
    TURING.字库_加载六十四进制识别字库(dict_func())     -- [VIP]
    local 识别结果 = TURING.识别(75)
    if 识别结果 ~= nil and 识别结果 ~= "" then    -- 注意：空值判断
        print('识别结果:',识别结果)
        return 识别结果
    end
end
-- 通用数字识别方法（重载版本，支持两个二值化参数，使用正确的TURING语法）
-- 参数：
--   x1, y1, x2, y2: 识别区域坐标
--   filter_range1: 第一个滤镜范围，如 "0-166"
--   filter_range2: 第二个滤镜范围，如 "0-95"
--   cut_x, cut_y: 切割参数（如果都是-1，则使用连通切割方式）
--   dict_func: 字库函数
--   confidence: 识别置信度（可选，默认为75）
-- 返回值：识别到的数字字符串（如 "80,10"），如果识别失败返回nil
function Tools.recognize_number_in_range_dual_filter(x1, y1, x2, y2, filter_range1, filter_range2, cut_x, cut_y, dict_func, confidence)
    -- 设置默认值
    confidence = confidence or 75
    
    -- 准备识别字库（使用正确的格式）
    local 识别字库
    if type(dict_func) == "function" then
        识别字库 = {六十四进制字库数组={dict_func()}}
    else
        识别字库 = {六十四进制字库数组={dict_func}}
    end
    
    -- 第一次识别：使用第一个滤镜参数
    local result1
    if cut_x == -1 and cut_y == -1 then
        -- 连通切割方式
        result1 = TURING.图灵识别({{加载图片={x1, y1, x2, y2}}, {{二值化={filter_range1}}, {延伸裁剪={cut_x, cut_y}}}, {连通区域={true}}, 识别字库, {confidence}})
    else
        -- 范围切割方式
        result1 = TURING.图灵识别({{加载图片={x1, y1, x2, y2}}, {{二值化={filter_range1}}, {延伸裁剪={cut_x, cut_y}}}, 识别字库, {confidence}})
    end
    
    -- 检查第一次识别结果
    if result1 ~= nil and result1 ~= "" and not string.find(result1, "?") then
        -- 检查是否为正确的数字格式（如：80,10 或 0,,80）
        local isValidFormat = Tools.is_valid_number_format(result1)
        if isValidFormat then
            print('第一次识别成功，结果格式正确:', result1)
            return result1  -- 返回原始识别结果，不转换为数字
        else
            print('第一次识别结果格式不正确:', result1)
        end
    else
        print('第一次识别结果为空或包含问号，尝试第二次识别')
    end
    
    -- 第二次识别：使用第二个滤镜参数
    print("第二次识别：使用滤镜参数 " .. filter_range2)
    local result2
    if cut_x == -1 and cut_y == -1 then
        -- 连通切割方式
        result2 = TURING.图灵识别({{加载图片={x1, y1, x2, y2}}, {{二值化={filter_range2}}, {延伸裁剪={cut_x, cut_y}}}, {连通区域={true}}, 识别字库, {confidence}})
    else
        -- 范围切割方式
        result2 = TURING.图灵识别({{加载图片={x1, y1, x2, y2}}, {{二值化={filter_range2}}, {延伸裁剪={cut_x, cut_y}}}, 识别字库, {confidence}})
    end
    
    print('第二次识别结果:', result2)
    sleep(300)
    
    -- 检查第二次识别结果
    if result2 ~= nil and result2 ~= "" then
        -- 检查是否为正确的数字格式（如：80,10 或 0,,80）
        local isValidFormat = Tools.is_valid_number_format(result2)
        if isValidFormat then
            print('第二次识别成功，结果格式正确:', result2)
            return result2  -- 返回原始识别结果，不转换为数字
        else
            print('第二次识别结果格式不正确:', result2)
            return nil
        end
    else
        print('第二次识别结果为空')
        return nil
    end
end

print("Tools.lua 通用工具库已加载")
        

return Tools 